package interviewcoding.similarity;

import java.util.*;

/**
 * sim = A * B / (|A| * |B|)
 */
public class CosineSimilarity {
    
    // 计算每个单词的词频，采用HashMap的数据结构
    private static Map<String, Integer> computeWordFrequency(String text) {
        Map<String, Integer> cnt = new HashMap<>();
        String[] words = text.split("\\W+");
        for (String word : words) {
            cnt.put(word, cnt.getOrDefault(word, 0) + 1);
        }
        return cnt;
    }


    // 计算两个向量的点积 求 A * B
    private static int computeDotProduct(Map<String, Integer> map1, Map<String, Integer> map2) {
        int sum = 0;
        for (String word : map1.keySet()) {
            sum += map1.getOrDefault(word, 0) * map2.getOrDefault(word, 0);
        }
        return sum;
    }
    // 计算向量的模长 求 |A| 或者 |B|  模长 = Math.sqrt(a^2 + b^2 + ...)
    private static double computeMagnitude(Map<String, Integer> map) {
        double sum = 0;
        for (int value : map.values()) {
            sum += value * value;
        }
        return Math.sqrt(sum);
    }

    // 计算余弦相似度
    public static double computeSimilarity(String text1, String text2) {
        // 计算文本的每个单词的词频
        Map<String, Integer> map1 = computeWordFrequency(text1);
        Map<String, Integer> map2 = computeWordFrequency(text2);
        // 计算单词向量模长
        double magnitude1 = computeMagnitude(map1);
        double magnitude2 = computeMagnitude(map2);
        // 计算两个向量的点积
        int dotProduct = computeDotProduct(map1, map2);
        return dotProduct / (magnitude1 * magnitude2);
    }
    
    // 测试代码
    public static void main(String[] args) {
        // 使用有道翻译题目
        String text1 = "Use Java code to calculate the similarity of two strings, and use percentage to represent the result of similarity. Full, running Java code is required";
        // 使用百度翻译题目
        String text2 = "Write Java code to calculate the similarity between two strings, and use percentages to represent the similarity results. Require complete and runnable Java code";
        double similarity = computeSimilarity(text1, text2);
        System.out.println("Cosine similarity: " + similarity);
    }
}
